package com.gaoxk.asserviceinterceptor;

import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 入站日志拦截器：不依赖CachedInputStream和Output类
 */
public class PureLoggingInInterceptor extends AbstractSoapInterceptor {
    private static final Logger log = LoggerFactory.getLogger(PureLoggingInInterceptor.class);
    // 存储请求开始时间（使用线程安全的Map替代ThreadLocal）
    private final Map<Long, Long> requestStartTimeMap = new ConcurrentHashMap<>();
    // 生成请求ID
    private final AtomicLong requestIdGenerator = new AtomicLong(0);

    public PureLoggingInInterceptor() {
        super(Phase.RECEIVE); // 在接收阶段拦截
    }

    @Override
    public void handleMessage(SoapMessage message) throws Fault {
        // 生成唯一请求ID
        long requestId = requestIdGenerator.incrementAndGet();
        // 记录请求开始时间
        long startTime = System.currentTimeMillis();
        requestStartTimeMap.put(requestId, startTime);
        
        try {
            // 1. 打印HTTP请求头
            log.info("===== 请求[{}] 开始 [{}] =====", requestId, startTime);
            printHttpRequestHeaders(message, requestId);
            
            // 2. 打印SOAP头
            printSoapHeaders(message, requestId);
            
            // 3. 读取并打印SOAP请求报文
            printSoapRequest(message, requestId);
            
            // 将请求ID存入消息，供出站拦截器使用
            message.put("REQUEST_ID", requestId);
            
        } catch (Exception e) {
            log.error("请求[{}]日志处理失败", requestId, e);
        }
    }

    /**
     * 打印HTTP请求头
     */
    private void printHttpRequestHeaders(SoapMessage message, long requestId) {
        try {
            // 获取HTTP请求头
            Map<String, Object> headers = (Map<String, Object>) message.get(Message.PROTOCOL_HEADERS);
            if (headers != null && !headers.isEmpty()) {
                log.info("请求[{}] HTTP头信息：", requestId);
                for (Map.Entry<String, Object> entry : headers.entrySet()) {
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    log.info("请求[{}]   {}: {}", requestId, key, value);
                }
            } else {
                log.info("请求[{}] 无HTTP头信息", requestId);
            }
        } catch (Exception e) {
            log.warn("请求[{}]读取HTTP头失败", requestId, e);
        }
    }

    /**
     * 打印SOAP头
     */
    private void printSoapHeaders(SoapMessage message, long requestId) {
        try {
            List<Header> soapHeaders = message.getHeaders();
            if (soapHeaders != null && !soapHeaders.isEmpty()) {
                log.info("请求[{}] SOAP头信息：", requestId);
                for (Header header : soapHeaders) {
                    log.info("请求[{}]   {}: {}", requestId, header.getName(), header.getObject());
                }
            } else {
                log.info("请求[{}] 无SOAP头信息", requestId);
            }
        } catch (Exception e) {
            log.warn("请求[{}]读取SOAP头失败", requestId, e);
        }
    }

    /**
     * 读取并打印SOAP请求报文
     */
    private void printSoapRequest(SoapMessage message, long requestId) throws IOException {
        // 获取原始输入流
        InputStream is = message.getContent(InputStream.class);
        if (is == null) {
            log.info("请求[{}] 无请求报文", requestId);
            return;
        }

        // 使用标准流缓存内容
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1) {
            baos.write(buffer, 0, len);
        }
        baos.flush();

        // 转换为字符串
        byte[] bytes = baos.toByteArray();
        String requestXml = new String(bytes, StandardCharsets.UTF_8);

        // 格式化XML并打印
        String formattedXml = formatXml(requestXml);
        log.debug("请求[{}] SOAP报文：\n{}", requestId, formattedXml);

        // 重置输入流（使用新的ByteArrayInputStream）
        message.setContent(InputStream.class, new java.io.ByteArrayInputStream(bytes));
    }

    /**
     * 简易XML格式化（无第三方依赖）
     */
    public static String formatXml(String xml) {
        if (xml == null || xml.trim().isEmpty()) {
            return "";
        }
        
        // 简易格式化逻辑（仅处理标签缩进）
        xml = xml.replace("><", ">\n<");
        StringBuilder sb = new StringBuilder();
        int indent = 0;
        String[] lines = xml.split("\n");
        
        for (String line : lines) {
            String trimmedLine = line.trim();
            if (trimmedLine.startsWith("</")) {
                indent--;
            }
            
            // 添加缩进
            for (int i = 0; i < indent; i++) {
                sb.append("  ");
            }
            sb.append(trimmedLine).append("\n");
            
            if (trimmedLine.startsWith("<") && !trimmedLine.startsWith("</") && !trimmedLine.endsWith("/>")) {
                indent++;
            }
        }
        return sb.toString();
    }

    /**
     * 获取请求开始时间（供出站拦截器使用）
     */
    public long getStartTime(long requestId) {
        return requestStartTimeMap.getOrDefault(requestId, System.currentTimeMillis());
    }

    /**
     * 移除已处理的请求时间（防止内存泄漏）
     */
    public void removeStartTime(long requestId) {
        requestStartTimeMap.remove(requestId);
    }
}
